/*	
 * Form	related	scripts.
 *	
 * @author Li Yang (young-lee@21cn.com)	
 */	

var Yform = {
	getEnhancedElements: function(form) {
		return Yutil.en.getEnhancedByFn(form, Yform.enhance);
	},
	
	enhance: function(elem) {
		if (elem.type == 'hidden') return false;
		if ('no_en'.hasClass(elem)) return false;

		Yform.fixIdIfNeeded(elem);
		
		var form = Yform.enclosingForm(elem);
		if (form) { // is in a "form"?
			Yform.markFieldHeadAndBody(elem);
			if (!'no_lbl'.hasClass(form))
				Yform.fixLabelIfNeeded(elem);
			
			if('disabled'.hasClass(form))
				elem.setAttribute('disabled', 'true');
			
			if('chg'.hasClass(form) && !'no_chg'.hasClass(elem)){
				elem.change_observer = function(){Yform.onElementChange(elem)};
				Event.observe(elem, "change", elem.change_observer);
			}
		}
		
		elem.focus_observer = function() {Yform.onElementFocus(elem)};
		elem.blur_observer = function() {Yform.onElementBlur(elem)};

		Event.observe(elem, "focus", elem.focus_observer);
		Event.observe(elem, "blur", elem.blur_observer);
		
		if (typeof(tinyMCE) != 'undefined' && 'textarea'.isTagOf(elem) && 'rich'.hasClass(elem))
			tinyMCE.execCommand("mceAddControl", false, elem.id);
		
		if (typeof(scwShow) == 'function' && 'date'.hasClass(elem)) {
			var cal = "<img src='web/images/icon-select-date.gif' style='cursor:pointer'/>".createElement();
			elem.parentNode.insertBefore(cal, elem.nextSibling);
			Event.observe(cal, 'click', function() { scwShow(elem, cal); });
		}
		
		//Check maxlength for textarea
		if( 'textarea'.isTagOf(elem)  && elem.getAttribute('maxlength')){
			Event.observe(elem, 'keydown', function(event){Yform.chkTaKeyDown(elem, event);});
			Event.observe(elem, 'paste', function(event){Yform.chkTaPaste(elem, event);});
		}
		return true;
	},
	
	deenhance: function(elem) {
		Event.stopObserving(elem, "focus", elem.focus_observer);
		Event.stopObserving(elem, "blur", elem.blur_observer);
		elem.focus_observer = null;
		elem.blur_observer = null;
		
		if (typeof(tinyMCE) != 'undefined'
			&& elem.tagName.toLowerCase() == "textarea" && "rich".hasClass(elem))
			tinyMCE.execCommand("mceRemoveControl", false, elem.id);
	},
	
	enclosingForm: function(elem) {
		elem = $(elem);
		if (!elem) return null;
		for (var p = elem.parentNode; p != null && p != document.body; p = p.parentNode)
			if ("form".hasClass(p))
				return p;
		return null;
	},
	
	markFieldHeadAndBody: function(elem) {
		if (!elem.name) return;

		var f, fbody, fhead;
		if ((f = "dl".ascendantOf(elem)) && "form".hasClass(f)) /*Young, Abacus: rollback.*/ {
			// <dt>, <dd> structure implies head and body
			fbody = "dd".ascendantOf(elem);
			fhead = "dt".previousOf(fbody);
		} else if ((f = "table".ascendantOf(elem)) && "form".hasClass(f)) {
			// <th>, <td> structure implies head and body
			fbody = "td".ascendantOf(elem);
			fhead = "th".previousOf(fbody);
		}
		
		if (fbody) fbody.setAttribute("id", elem.name + "_fbody");
		if (fhead) fhead.setAttribute("id", elem.name + "_fhead");
		if ("required".hasClass(elem)) {
			if (fbody) "required".addClass(fbody);
			//add * for required class to satisfy accessibility requirement
			if(fhead){
				"required".addClass(fhead);
				if(fhead.innerHTML.length >0 && fhead.innerHTML.charAt(0) != '*')
					fhead.innerHTML = '*' + fhead.innerHTML;
			}
		}
	},
	
	fheadOf: function(elemOrName) {
		// important naming convention
		return $((elemOrName.name ? elemOrName.name : elemOrName) + "_fhead");
	},
	
	fbodyOf: function(elemOrName) {
		// important naming convention
		return $((elemOrName.name ? elemOrName.name : elemOrName) + "_fbody");
	},
	
	errorOf: function(elemOrName) {
		// important naming convention
		return $((elemOrName.name ? elemOrName.name : elemOrName) + "_error");
	},
	
	fixIdIfNeeded: function(elem) {
		if (!elem.id && elem.name) {
			var base = elem.name, id = elem.name;
			if ($(id) != null && $(id) != elem) { // to work with IE
				for (var ver = 2; $(id = base + ver) != null; ver++);
			}
			elem.setAttribute("id", id);
		}
	},
	
	fixLabelIfNeeded: function(elem) {
		if (!elem.id || 'hidden'.hasClass(elem)) return;
		
		var label = jQuery.find('label[@for='+elem.id+']')[0];
		if (!label) {
			var t = Yform.fheadOf(elem);
			if (!t)
				t = 'previousSibling';
			if (elem.type && ('checkbox'==elem.type || 'radio'==elem.type))
				t = 'nextSibling';
			if (t.constructor == String) {
				// find a sibling to be label
				var sib = elem, text;
				while (sib = sib[t]) {
					text = sib.nodeType == 1 ? sib.innerHTML.stripTags() : sib.data;
					if (text.trim().length > 1)
						break;
				}
				if (sib) {
					label = ("<label for='"+elem.id+"'></label>").createElement();
					sib.parentNode.insertBefore(label, sib);
					label.appendChild(sib);
				}
			} else {
				// wrap <dt> (the field head) as label
				t.innerHTML = "<label for='"+elem.id+"'>" + t.innerHTML + "</label>";
				label = t.firstChild;
			}
		}
		
		Yform.fixAccessKeyIfNeeded(elem, label);
	},
	
	fixAccessKeyIfNeeded: function(elem, label) {
		if (!label) return;
		
		var texts = Yutil.textNodes(label);
		var t = null, idx, key, c;

		key = elem.accessKey || elem.getAttribute('accesskey') || label.accessKey;
		if (key) {
			key = key.toLowerCase();
			for (var i = 0; i < texts.length && !t; i++)
				if ((idx = texts[i].data.toLowerCase().indexOf(key)) >= 0) {
					t = texts[i];
					key = texts[i].data.charAt(idx);
				}
		} else {
			for (var i = 0; i < texts.length && !key; i++) {
				t = texts[i];
				for (idx = 0; idx < t.data.length && !key; idx++) {
					c = t.data.charAt(idx).toLowerCase();
					if ((c>='a' && c<='z' && c!='d' || c>='0' && c<='9')
						&& jQuery.find('label[@accesskey='+c+']').length == 0
						&& jQuery.find('a[@accesskey='+c+']').length == 0
						&& jQuery.find('button[@accesskey='+c+']').length == 0
						&& jQuery.find('input[@accesskey='+c+']').length == 0
						&& jQuery.find('select[@accesskey='+c+']').length == 0
						&& jQuery.find('textarea[@accesskey='+c+']').length == 0)
						key = t.data.charAt(idx);
				}
			}
			idx--;
		}
		
		if (t && key) {
			elem.accessKey = key.toLowerCase();
			label.accessKey = key.toLowerCase();
			t.parentNode.insertBefore(document.createTextNode(t.data.substring(0, idx)), t);
			t.parentNode.insertBefore(('<u>'+key+'</u').createElement(), t);
			t.data = t.data.substring(idx + 1);
		}
	},
	
	markError: function(elem, errmsg) {
		elem = $(elem);
		"error".addClass(elem);
		
		var fbody = Yform.fbodyOf(elem);
		var fhead = Yform.fheadOf(elem);
		if (fbody) "error".addClass(fbody);
		if (fhead) "error".addClass(fhead);

		var error = Yform.errorOf(elem);

		if (error == null) {
			error = document.createElement("div");
			error.setAttribute("id", elem.name + "_error");
			// insert error div
			var fbody = Yform.fbodyOf(elem);
			if (fbody)
				fbody.appendChild(error);
			else
				elem.parentNode.insertBefore(error, elem.nextSibling);
		}

		error.innerHTML += "<p class='error'>" + errmsg + "</p>";
		Element.show(error);
		return false;
	},
	
	clearError: function(elem) {
		elem = $(elem);
		"error".removeClass(elem);
		
		var fbody = Yform.fbodyOf(elem);
		var fhead = Yform.fheadOf(elem);
		if (fbody) "error".removeClass(fbody);
		if (fhead) "error".removeClass(fhead);

		var error = Yform.errorOf(elem);
		if (error) {
			error.innerHTML = "";
			Element.hide(error);
		}
	},
	
	clearErrors: function(form) {
		form = form || document;
		
		var elems = Yform.getEnhancedElements(form);
		for (var i = 0; i < elems.length; i++) {
			Yform.clearError(elems[i]);
		}
	},
	
	validateAllOnSubmit: function(btn) {
		var form = Yform.enclosingForm(btn);
		var valid = !form || Yform.validateAll(form, true);
		if (valid)
			return true;
		alert('Some information needs to be corrected before continuing.');
		return false;
	},
	
	validateAll: function(form, focus) {
		form = form || document;
		
		var result = true, first = null;
		var elems = Yform.getEnhancedElements(form);
		for (var i = 0; i < elems.length; i++) {
			result = Yform.validate(elems[i]) && result;
			if (!result && !first)
				first = elems[i];
		}
		
		if (focus && first)
			first.focus();
		return result ? true: false;
	},
	
	validate: function(elem) {
		var result = true;
		Yform.clearError(elem);
		var value = Form.Element.getValue(elem);
	
		// validate by class
		var classes = elem.className.split(/\s+/);
		for (var i = 0; i < classes.length; i++) {
			var handler = Yform["validate_" + classes[i]];
			if (handler)
				result = handler(elem, value) && result;
		}
		
		// special: textarea maxlength
		if ("textarea".isTagOf(elem) && elem.getAttribute("maxlength"))
			result = Yform.validateMaxLength(elem, value) && result;
		
		// custom validate
		if (elem.validate)
			result = elem.validate(elem, value) && result;
		
		return result ? true : false;
	},
	
	validate_required: function(elem, value) {
		if (value == null || typeof value=='string' && value.match(/^\s*$/) || value instanceof Array && elem.options.length == 0){
			return Yform.markError(elem, "Required");
		}

		return true;
	},
	
	validate_integer: function(elem, value) {
		if (value.trim().length > 0 && !value.match(/^\s*-?\d+[\d,]*\s*$/))
			return Yform.markError(elem, "Invalid integer");
		return true;
	},
	
	validate_number: function(elem, value) {
		if (value.trim().length > 0 && !value.match(/^\s*-?((\d+[\d,]*)|(\d+[\d,]*\.\d+))(E\d+)?\s*$/))
			return Yform.markError(elem, "Invalid number");
		return true;
	},
	
	
	validate_positive: function(elem, value) {
		if (value.trim().length > 0 && value.match(/^\s*-|^\s*0+\.?0*\s*$/))
			return Yform.markError(elem, "Should be positive");
		return true;
	},
	
	validate_positive0: function(elem, value) {
		if (value.trim().length > 0 && value.match(/^\s*-/))
			return Yform.markError(elem, "Should be positive or zero");
		return true;
	},
	
	validate_email: function(elem, value) {
		if (value.trim().length > 0 && !value.match(/^[\w\-\.]+@[\w\-\.]+$/))
			return Yform.markError(elem, "Invalid email");
		return true;
	},
	
	validate_date: function(elem, value) {
		if (value.trim().length > 0) {
			try {
				var date = parseDateString(value);
				elem.value = date.getFullYear() + '-' + (date.getMonth()+1) + '-' + date.getDate();
			} catch (e) {
				return Yform.markError(elem, e.message);
			}
		}
		return true;
	},
	
	validateMaxLength: function(elem, value) {
		var maxlen = elem.getAttribute("maxlength");
		if (value.length > maxlen)
			return Yform.markError(elem, "No more than " + maxlen + " chars, now " + value.length);
		return true;
	},
	
	onElementFocus: function(elem) {
		"active".addClass(elem);

		var fbody = Yform.fbodyOf(elem);
		var fhead = Yform.fheadOf(elem);
		if (fbody) "active".addClass(fbody);
		if (fhead) "active".addClass(fhead);
	},
	
	onElementBlur: function(elem) {
		"active".removeClass(elem);

		var fbody = Yform.fbodyOf(elem);
		var fhead = Yform.fheadOf(elem);
		if (fbody) "active".removeClass(fbody);
		if (fhead) "active".removeClass(fhead);

		// parse date
		if ("date".hasClass(elem)) {
			try {
				var date = parseDateString(elem.value);
				elem.value = date.getFullYear() + '-' + (date.getMonth()+1) + '-' + date.getDate();
			} catch (e) {
			}
		}
	},
	
	onElementChange: function(elem){
		if(!$('_changes')){
			var _changes = ("<div id='_changes' class='hidden'></div>").createElement();
			document.body.appendChild(_changes);
		}
		$('_changes').isChanged = true;
	},
	
	// Check the max length of textarea when input using keyboard
	chkTaKeyDown: function(elem, event){
		event = event || window.event;
		var maxlen = elem.getAttribute('maxlength');
		var key = window.event ? event.keyCode : event.which;
		if(maxlen && (elem.value.length > maxlen -1) && ((key == 32) || (key ==13) || (key > 47))){
			alert('Kindly noted the max length is set to ' + maxlen + ' characters.' );
			elem.value = elem.value.substr(0, maxlen);
			Event.stop(event);
			return false;
		}
	},
	
	//Check the max length of textarea when pasting, only applies to IE currently
	chkTaPaste: function(elem, event){
		event = event || window.event;
		var maxlen = elem.getAttribute('maxlength');
		if(maxlen && window.event){
			var paste = window.clipboardData.getData('Text');
			if((elem.value.length + paste.length) > maxlen){
				alert('Kindly noted the max length is set to ' + maxlen + ' characters.' );
				elem.value = elem.value + paste.substr(0, paste.length - maxlen);
				Event.stop(event);
				return false;
			}
		}
	}
}

// init tinyMCE -- rich textarea
if (typeof(tinyMCE) != 'undefined') {
	tinyMCE.init({
		mode: "exact",
		elems: "",
		theme: "advanced",
		plugins: "table,print,contextmenu,fullscreen",
		theme_advanced_buttons1: "bold,italic,underline,strikethrough,separator,fontselect,fontsizeselect,forecolor,backcolor,removeformat,separator,numlist,bullist,outdent,indent,separator,justifyleft,justifycenter,justifyright,separator,link,image,separator,fullscreen,print,code",
		theme_advanced_buttons2: "",
		theme_advanced_buttons3: "",
		theme_advanced_toolbar_location: "top",
		theme_advanced_toolbar_align: "left",
		theme_advanced_path_location: "bottom",
		theme_advanced_resizing: true,
		theme_advanced_resize_horizontal: false,
		accessibility_focus: false,
		apply_source_formatting: true
	}); 
}

// register enhancement
Yutil.en.register("input,select,textarea", Yform.enhance, Yform.deenhance);
